/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 *Truth: I Believe in Spring Brother~
 */
package electsys;

import com.google.gdata.client.*;
import com.google.gdata.client.calendar.*;
import com.google.gdata.data.*;
import com.google.gdata.data.extensions.*;
import com.google.gdata.util.*;

import java.net.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author t
 * Created 2010-7-17  16:52:41
 * Last Modified 2010-7-17  16:52:41
 *
 */
public class GCalendar {

    public static String CLIENTNAME = "SJTU-LITTLET_GDATA_CLIENT-1";
    public static String SERVICENAME = "cl";
    public static String DefaultURL = "http://www.google.com/calendar/feeds/username/private/full";
    public static String DefaultWhereRel = "The Classroom";
    public static String DefaultWherelabel = "SJTU";
    public static String DefaultContentLabel = "LGC";
    public static String DefaultContentVersion = "2";
    public String username = "";
    public String password = "";
    public CalendarService myService = null;
    public boolean login = false;

    public GCalendar() {
        myService = new CalendarService(GCalendar.CLIENTNAME);
        myService.setProtocolVersion(CalendarService.Versions.V1);
    }

    public GCalendar(String un, String ps) {
        myService = new CalendarService(GCalendar.CLIENTNAME);
        myService.setProtocolVersion(CalendarService.Versions.V1);
        setUserPass(un, ps);
    }

    public boolean setUserPass(String u, String p) {
        if (u == null || p == null) {
            return false;
        }
        this.username = u;
        this.password = p;
        try {
            if (this.myService == null) {
                myService = new CalendarService(GCalendar.CLIENTNAME);
            }
            myService.setUserCredentials(username, password);
            this.login = true;
        } catch (AuthenticationException ex) {
            this.login = false;
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
        return true;
    }

    public EventEntry insertEvent(EventEntry entry) {
        if (entry == null) {
            return null;
        }
        URL postUrl = null;
        EventEntry insertedEntry = null;
        if (username.equals("") || password.equals("")) {
            Logger.getLogger(GCalendar.class.getName()).info("Username or Password not set..");
            return null;
        }
        try {
            //System.out.println(new String(GCalendar.DefaultURL).replaceFirst("username", username));
            postUrl = new URL(new String(GCalendar.DefaultURL).replaceFirst("username", username));
        } catch (MalformedURLException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            return insertedEntry = myService.insert(postUrl, entry);
            //System.out.println(entry.getLocations().size());
            //System.out.println(entry.getTimes().size());
            //System.out.println(insertedEntry.getLocations().size());
        } catch (IOException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ServiceException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        }

        return null;
    }

    public EventEntry createEventWhen(String title, String content, String author, String stime, String etime, String where) {
        EventEntry myEntry = new EventEntry();
        if (title != null) {
            myEntry.setTitle(new PlainTextConstruct(title));
        }

        if (content != null) {
            if (!content.startsWith(GCalendar.DefaultContentLabel)) {
                content = GCalendar.DefaultContentLabel + GCalendar.DefaultContentVersion + " " + content;
            }
            myEntry.setContent(new PlainTextConstruct(content));
        }

        if (author != null) {
            Person myAuthor = new Person(author, null, username);
            myEntry.getAuthors().add(myAuthor);
        }

        DateTime startTime = null;
        DateTime endTime = null;
        if (stime != null) {
            startTime = DateTime.parseDateTime(stime);//"2006-04-17T15:00:00-08:00"
        }
        if (etime != null) {
            endTime = DateTime.parseDateTime(etime);//"2006-04-17T17:00:00-08:00"
        }
        When eventTimes = new When();
        eventTimes.setStartTime(startTime);
        eventTimes.setEndTime(endTime);
        myEntry.addTime(eventTimes);

        if (where != null) {
            Where myWhere = new Where(GCalendar.DefaultWhereRel, GCalendar.DefaultWherelabel, where);
            myEntry.addLocation(myWhere);
        }

        return myEntry;
    }

    public EventEntry createEventRecurrence(String title, String content, String author, String recu, String where) {
        EventEntry myEntry = new EventEntry();
        if (title != null) {
            myEntry.setTitle(new PlainTextConstruct(title));
        }

        if (content != null) {
            if (!content.startsWith(GCalendar.DefaultContentLabel)) {
                content = GCalendar.DefaultContentLabel + GCalendar.DefaultContentVersion + " " + content;
            }
            myEntry.setContent(new PlainTextConstruct(content));
        }

        if (author != null) {
            Person myAuthor = new Person(author, null, username);
            myEntry.getAuthors().add(myAuthor);
        }

        if (recu == null) {
            recu = new String("");
        }
        Recurrence rec = new Recurrence();
        rec.setValue(recu);
        System.out.println(recu);
        myEntry.setRecurrence(rec);

        //myEntry.addTime(null);


        if (where != null) {
            Where myWhere = new Where(GCalendar.DefaultWhereRel, GCalendar.DefaultWherelabel, where);
            myEntry.addLocation(myWhere);
        }

        return myEntry;
    }

    public EventFeed queryEvent(String key, DateTime st, DateTime end, int max) {
        if (username.equals("") || password.equals("") || key == null) {
            return null;
        }
        Query myQuery = null;
        EventFeed myFeed = null;
        try {
            myQuery = new Query(new URL(new String(GCalendar.DefaultURL).replaceFirst("username", username)));
            if (max > myQuery.getMaxResults()) {
                myQuery.setMaxResults(max);
            }
            if (st != null) {
                myQuery.setUpdatedMin(st);
            }
            if (end != null) {
                myQuery.setUpdatedMax(end);
            }
        } catch (MalformedURLException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        }
        myQuery.setFullTextQuery(key);
        try {
            myFeed = myService.query(myQuery, EventFeed.class);
        } catch (IOException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ServiceException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        }
        return myFeed;
    }

    public int queryEventNum(String key) {
        int max = 100;
        EventFeed ef = queryEvent(key, null, null, max);
        while (ef.getEntries().size() >= max) {
            max = max * 2;
            ef = queryEvent(key, null, null, max);
        }
        return ef.getEntries().size();
    }

    public EventEntry getEvent(EventEntry entry) {
        if (entry == null) {
            return null;
        }
        EventFeed myFeed = queryEvent(entry.getTitle().getPlainText(), null, null, 25);
        for (int i = 0; i < myFeed.getEntries().size(); i++) {
            if (GCalendar.eventIsEqual2(myFeed.getEntries().get(i), entry)) {
                //System.out.println("Get one");
                return myFeed.getEntries().get(i);
            }
        }
        return null;
    }

    public EventEntry updateEvent(EventEntry entry1, EventEntry entry2) {
        if (entry1 == null || entry2 == null) {
            return null;
        }
        URL updateUrl = null;
        try {
            updateUrl = new URL(entry1.getEditLink().getHref());
        } catch (MalformedURLException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            return myService.update(updateUrl, entry2);
        } catch (IOException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ServiceException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public void deleteEvent(EventEntry entry) {
        if (username.equals("") || password.equals("") || entry == null) {
            return;
        }
        URL deleteUrl = null;
        try {
            deleteUrl = new URL(entry.getEditLink().getHref());
            //System.out.println(deleteUrl);
            //System.out.println(deleteUrl.toString());
        } catch (MalformedURLException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            myService.delete(deleteUrl);
        } catch (IOException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ServiceException ex) {
            Logger.getLogger(GCalendar.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public static boolean eventIsEqual(EventEntry entry1, EventEntry entry2) {
        if (entry1.getTitle().equals(entry2.getTitle()) && entry1.getContent().equals(entry2.getContent()) && entry1.getTimes().equals(entry2.getTimes()) && entry1.getLocations().equals(entry2.getLocations())) {
            return true;
        }
        return false;
    }

    public static boolean eventIsEqual2(EventEntry entry1, EventEntry entry2) {
        if (entry1.getTitle().getPlainText().equals(entry2.getTitle().getPlainText()) && entry1.getPlainTextContent().equals(entry2.getPlainTextContent())) {
            return true;
        }
        return false;
    }

    //no use
    public String NormalizeTime(String time, String zone) {
        if (time == null) {
            return null;
        }
        if (zone == null) {
            zone = MyConst.TIMEZONE;
        }
        //2010-07-22T13:50:00-08:00
        return "";
    }

    public List<Calendar> getDateOfWeek(Calendar start, int maxweek) {
        List<Calendar> dow = new ArrayList();
        //Calendar cal = Calendar.getInstance();
        Date date = start.getTime();
        //System.out.println(date.toString());
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (int i = 0; i < maxweek; i++) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(Calendar.DAY_OF_YEAR, i * 7);
            //System.out.println(cal.getTime().toString());
            dow.add(cal);
            //System.out.println(sdf.format(date));
            //cal.add(Calendar.DAY_OF_YEAR, 7);
            //date = cal.getTime();
        }
        return dow;
    }

    public String getRecuFromLesson(Calendar cal,LessonInfo li) {
        String ret = new String();
        if (li==null || cal==null) {
            return ret;
        }
        Date date = cal.getTime();
        Calendar tmp = Calendar.getInstance();
        tmp.setTime(date);
        tmp.add(Calendar.DAY_OF_YEAR, (li.weeks.get(0).intValue()-1) * 7 + li.dayOfWeek);
        date = tmp.getTime();
        String inter = new String();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        if (li.weeks.size() <= 1) {
            inter = inter + "1";
        } else {
            inter = inter + String.valueOf(li.weeks.get(1).intValue() - li.weeks.get(0).intValue());
        }
        //DTSTART;TZID=Asia/Shanghai:20100725T160000\r\nDURATION:3H\r\nRRULE:FREQ=WEEKLY;COUNT=10;INTERVAL=2;BYDAY=SU\r\n
        ret = ret + "DTSTART;TZID=" + MyConst.TZID + ":";
        ret = ret + sdf.format(date) + "T" + li.startTime.substring(0, 2) + li.startTime.substring(3,5) + "00\r\n";
        ret = ret + "DURATION:" + String.valueOf(MyUtil.getDurationMin(li.startTime, li.endTime)) + "M\r\n" ;
        ret = ret + "RRULE:FREQ=WEEKLY;COUNT=" + String.valueOf(li.weeks.size()) + ";INTERVAL=" + inter;
        System.out.println(ret);
        return ret;
    }

    public List<EventEntry> getEventWhenFromLessonTB(LessonTable lessontb, List<String> bsids, Calendar cal) {
        if (lessontb == null) {
            return null;
        }
        List<LessonInfo> lis = lessontb.getAllLessons(bsids);
        List<Calendar> cals = this.getDateOfWeek(cal, lessontb.MaxWeek);
        List<EventEntry> ees = new ArrayList();
        for (LessonInfo info : lis) {
            List<String> st = info.getFormatedStartTime(cals, MyConst.TIMEZONE);
            List<String> et = info.getFormatedEndTime(cals, MyConst.TIMEZONE);
            for (int i = 0; i < st.size(); i++) {
                EventEntry eet = this.createEventWhen(info.name, info.id + " " + info.notes, null, st.get(i), et.get(i), info.classroom);
                ees.add(eet);
            }
        }
        return ees;
    }

    public List<EventEntry> getEventRecuFromLessonTB(LessonTable lt, List<String> bsids, Calendar cal) {
         if (lt == null) {
            return null;
        }
        List<LessonInfo> lis = lt.getAllLessons(bsids);
        List<EventEntry> ees = new ArrayList();
        for (LessonInfo info : lis) {
            EventEntry eet = this.createEventRecurrence(info.name, info.id + " " +info.notes , null,this.getRecuFromLesson(cal, info),info.classroom);
            ees.add(eet);
        }
        return ees;
    }

    public List<EventEntry> getEventFromExams(List<ExamInfo> eis) {
        if (eis == null) {
            return null;
        }
        List<EventEntry> ees = new ArrayList();
        for (ExamInfo ei : eis) {
            //System.out.println(ei.startTime + MyConst.TIMEZONE);
            EventEntry ee = this.createEventWhen(ei.name, ei.teacher + " " + ei.notes, null, ei.startTime + MyConst.TIMEZONE, ei.endTime + MyConst.TIMEZONE, ei.classroom);
            ees.add(ee);
        }
        return ees;
    }

    public void insertEvents(List<EventEntry> ees) {
        Logger.getLogger(GCalendar.class.getName()).info("Total: " + ees.size());
        for (int i = 0; i < ees.size(); i++) {
            this.insertEvent(ees.get(i));
            if (i % 10 == 0 || i == ees.size() - 1) {
                Logger.getLogger(GCalendar.class.getName()).info(String.valueOf(i + 1) + " done..");
            }
        }
    }

    public void clearLGC(String version) {
        EventFeed ef = queryEvent(GCalendar.DefaultContentLabel + version, null, null, 50);
        int count = 0;
        while (ef.getEntries().size() > 0) {
            for (int i = 0; i < ef.getEntries().size(); i++) {
                deleteEvent(ef.getEntries().get(i));
                count++;
                if (count % 10 == 0) {
                    Logger.getLogger(GCalendar.class.getName() + version).info("Deletion:  " + count + "  done..");
                }
            }
            ef = queryEvent(GCalendar.DefaultContentLabel + version, null, null, 50);
        }
        Logger.getLogger(GCalendar.class.getName() + version).info("Total Deletion:  " + count + "  done..");
    }
}
